package sunyu.controller.shiro.realm;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.stereotype.Component;
import sunyu.controller.shiro.pojo.ShiroInfo;
import sunyu.mapper.shiro.pojo.Resource;
import sunyu.mapper.shiro.pojo.Role;
import sunyu.mapper.shiro.pojo.User;
import sunyu.service.shiro.RoleService;
import sunyu.service.shiro.UserService;
import sunyu.tools.encrypt.EncryptTools;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 自定义Realm
 *
 * @author 孙宇
 */
@Component("myRealm")
public class MyRealm extends AuthorizingRealm {

    @javax.annotation.Resource(name = "encryptTools")
    private EncryptTools encryptTools;

    @javax.annotation.Resource(name = "userService")
    private UserService userService;

    @javax.annotation.Resource(name = "roleService")
    private RoleService roleService;

    /**
     * 在调用controller的方法时，如果方法上面有shiro注解，会触发下面的方法
     *
     * @param principalCollection
     *
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        ShiroInfo shiroInfo = (ShiroInfo) this.getAuthenticationCacheKey(principalCollection);
        info.setRoles(shiroInfo.getRoles());
        info.setStringPermissions(shiroInfo.getPermissions());
        return info;
    }

    /**
     * 调用subject.login(token);的时候，会触发下面的方法
     *
     * @param authenticationToken
     *
     * @return
     *
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String loginName = token.getUsername();
        Map<String, Object> params = new HashMap<String, Object>() {{
            put("loginName", loginName);
        }};
        List<User> users = userService.select(null, params);
        if (users != null && users.size() > 0) {
            User user = users.get(0);

            ShiroInfo shiroInfo = new ShiroInfo();
            shiroInfo.setUserId(user.getId());
            shiroInfo.setUserName(user.getName());
            shiroInfo.setUserLoginName(user.getLoginName());
            shiroInfo.setUserLoginPassword(user.getLoginPassword());

            Set<String> rolesSet = new HashSet<String>();
            Set<String> stringPermissionsSet = new HashSet<String>();
            List<Role> roles = userService.getRoles(user.getId());
            if (roles != null && roles.size() > 0) {
                for (Role role : roles) {
                    rolesSet.add(role.getName());//当前用户拥有的角色
                    List<Resource> resources = roleService.getResources(role.getId());
                    if (resources != null && resources.size() > 0) {
                        for (Resource resource : resources) {
                            stringPermissionsSet.add(resource.getPermission());//当前用户拥有的权限
                        }
                    }
                }
            }
            shiroInfo.setRoles(rolesSet);
            shiroInfo.setPermissions(stringPermissionsSet);

            AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(shiroInfo, user.getLoginPassword(), getName());
            return authenticationInfo;
        } else {
            throw new UnknownAccountException();
        }
    }
}
